// journal-lite is unique because: (1) it's a memory-buffered journal 
// that flushes only when needed or asked, and (2) it includes only
// meta-data about writes (namely the start and length of the write), 
// no data is included.

#ifndef __JOURNAL_LITE__
#define __JOURNAL_LITE__

#include <inttypes.h>
#include <cstdlib>
#include "st.h"

#ifdef __cplusplus
extern "C" {
#endif

// #include "backend-fs.h"

#define BUFFER_SIZE 2048

#pragma pack(push, 1)
struct JournalRecord 
{
	uint32_t begin;			// in 512-byte unit
	uint16_t length;		// in 512-byte unit, to save 1/4 space
};

// WARNING: struct JournalLite is supposed to be a member of struct Chunk!!!
struct JournalLite
{
	st_mutex_t update_jl_lock;
	uint64_t version0;		// chunk version before the following writes
	uint32_t njournals;
	struct JournalRecord journals[ BUFFER_SIZE ];
};

struct JRecordList
{
	uint64_t version0;		// chunk version before the following writes
	uint32_t njournals;
	struct JournalRecord* r;
};
#pragma pack(pop)

void journal_lite_flush(struct JournalLite* j);

static inline void journal_lite_init(struct JournalLite* j, uint64_t version0)
{
	j->version0 = version0;
	j->njournals = 0;
}

extern int journal_force_flush;
static inline void journal_lite_add(struct JournalLite* j, uint32_t begin, uint32_t length)
{
	if (j->version0 == (uint64_t)-1)
		return;

	uint32_t begin_s = begin / 512;
	uint32_t end_s = (begin + length + 511) / 512;
	j->journals[ j->njournals ].begin = begin_s;
	j->journals[ j->njournals ].length = (uint16_t)(end_s - begin_s);
	j->njournals++;

	if (j->njournals == BUFFER_SIZE || journal_force_flush){
		journal_lite_flush(j);
		j->njournals = 0;
	}
}

// read on-disk journals since version since_version, 
// and combine with in-memory journals j, 
// and sort and reduce the overlapped journals,
// then stores in *out_list,
// intended for use in journal-based fix (partial incubation)
int journal_lite_read(struct JournalLite* j, uint64_t since_version, struct JRecordList* out_list);

static inline void JRL_free(struct JRecordList* l)
{
	if(l->r)
		free(l->r);
	l->r = NULL;
	l->njournals = 0;
}

// removes the journal file
int journal_lite_remove(uint32_t volumeid, uint32_t index);

#ifdef __cplusplus
}
#endif

#endif

